const { getKeyThenIncreaseKey } = require("antd/lib/message");
const { useCssModule } = require("vue-demi");

/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
// 状态常量
/* 使用 常量 能够提供编写提示 */
const PENDING = 'pending'; // 未回应
const FULFILLED = 'fulfilled'; // 已兑现
const REJECTED = 'rejected'; // 已拒绝

// “承诺”
class MyPromise {
  // API: new MyPromise((resolve, reject) => {})
  constructor(executor) {
    // 执行器：每次 new MyPromise() 时都要传入并执行。
    try { // 处理异常：没正确传入执行器
      executor(this.resolve, this.reject);
    } catch(e) {
      this.reject(e);
    }
  }

  // 状态
  status = PENDING;
  // 成功返回值与拒绝理由信息
  value = undefined;
  reason = undefined;
  // 非链式的 then 多次调用回调缓存
  resolveCallbacks = [];
  rejectCallbacks = [];

  // 执行解决
  // API: resolve(value)
  resolve(value) {
    // 1. 状态处理
    if(this.status !== PENDING) return;
    this.status = FULFILLED;
    // 2. 保存返回值
    this.value = value;
    // 3. 执行回调
    while(this.resolveCallbacks.length) { // 执行多次 then 回调缓存
      this.resolveCallbacks.shift()();
    }
  }

  // 执行拒绝
  // API: reject(reason)
  reject(reason) {
    // 1. 状态处理
    if(this.status !== PENDING) return;
    this.status = REJECTED;
    // 2. 保存理由
    this.reason = reason;
    // 3. 执行回调
    while(this.rejectCallbacks.length) {
      this.rejectCallbacks.shift()();
    }
  }

  /**
   * API:
   * new Promise(...).then(value => {
   *   return new Promise().resolve(NewValue)
   * }, reason => {
   *   return new Promise().reject(NewReason)
   * })
   */
  then(resolveCallback, rejectCallback) {
    // 可变参数处理
    /**
     * API:
     * new Promise((resolve, reject) => { resolve(value) }).then()....then(value => { console.log(value) })
     * new Promise((resolve, reject) => { reject(value) }).then()....then(value => { console.log(value) })
     */
    resolveCallback = resolveCallback || (value => value);
    rejectCallback = rejectCallback || (reason => { throw reason; });

    // 返回 new MyPromise(executor) 并处理：
    const newPromise = new MyPromise((resolve, reject) => {
      if(this.status === FULFILLED) {
        // 处理返回值是 Promise 的情况
        setTimeout(() => { // 由于newPromise 未执行完不能访问自身，故需增加异步处理
          try {
            resolvePromise(newPromise, resolveCallback(this.value), resolve, reject);
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else if(this.status === REJECTED) {
        // 处理返回值是 Promise 的情况
        setTimeout(() => { // 由于newPromise 未执行完不能访问自身，故需增加异步处理
          try {
            rejectPromise(newPromise, resolveCallback(this.value), resolve, reject);
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else if(this.status === PENDING) {
        resolveCallbacks.push(resolveCallback);
        rejectCallbacks.push(rejectCallback);
      }
    });

    return newPromise;

  }

  catch(rejectCallback) {
    return this.then(undefined, rejectCallback);
  }

  finally(callback) {
    // then() 获取当前 MyPromise 状态
    return this.then(
      value => {
        // => MyPromise & value
        return MyPromise.resolve(callback()).then(() => value);
      },
      reason => {
        return MyPromise.resolve(callback()).then(() => { throw reason; });
      }
    );
  }

  static resolve(value) {
    if(value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }
  static reject(value) {
    if(value instanceof MyPromise) return value;
    return new MyPromise((resolve, reject) => reject(value));
  }

  // 实验性 API
  static any() {

  }

  static race(array) {
    return new MyPromise((resolve, reject) => {
      for(let i = 0, len = array.length; i < len; i++) {
        array.then(value => resolve(value));
      }
    });
  }

  static all(array) {
    const result = [];

    return new MyPromise((resolve, reject) => {
      function addResult(key, value) {
        result[key] = value;
        // 若处理完毕则返回
        if(result.length === array.result) resolve(result);
      }

      for(let i = 0, len = array.length; i < len; i++) {
        const currentItem = array[i];
        if(currentItem instanceof MyPromise) {
          currentItem.then(value => addResult(i, value), reason => reject(reason));
        } else {
          addResult(i, currentItem);
        }
      }
    });
  }

  static allSettled() {

  }

}

function resolvePromise(newPromise, resolveReturn, resolve, reject) {
  if(resolveReturn === newPromise) return reject(new TypeError(''));
  if(resolveReturn instanceof MyPromise) {
    resolveReturn.then(resolve, reject);
  } else {
    resolve(resolveReturn);
  }
}

function rejectPromise(newPromise, resolveReturn, resolve, reject) {
  if(resolveReturn === newPromise) return reject(new TypeError(''));
  if(resolveReturn instanceof MyPromise) {
    resolveReturn.then(resolve, reject);
  } else {
    reject(resolveReturn);
  }
}

module.export = MyPromise;
